package com.zdf.license.verify.listener;

import com.zdf.license.core.model.LicenseExtraParam;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 增加业务系统中自定义证书验证监听器
 */
public abstract class ACustomVerifyListener<T> {

    /** 软件证书参数全局验证监听容器 */
    private static final List<ACustomVerifyListener<?>> CUSTOM_VERIFY_LISTENER_LIST = new ArrayList<>(16);
    public static List<ACustomVerifyListener<?>> getCustomListenerList(){
        return CUSTOM_VERIFY_LISTENER_LIST;
    }
    public synchronized static void addCustomListener(ACustomVerifyListener<?> verifyListener){
        CUSTOM_VERIFY_LISTENER_LIST.add(verifyListener);
    }

    private T custom;

    /**
     * 默认构造函数，干了一件事情，就是会把所有实现了这个抽象类的子类实例全部添加到全局自定义验证监听器列表中
     * 因为在调用子类的构造函数时，会首先调用父类的构造器
     */
    public ACustomVerifyListener() {
        addCustomListener(this);
    }

    /**
     * 业务系统自定义证书认证方法
     * @param licenseExtra 自定义验证参数
     */
    public final void install(LicenseExtraParam licenseExtra) {
        ParamType paramType = paramType();
        Map<String, Object> licenseExtraParams = licenseExtra.getParams();
        Object custom = licenseExtraParams.get(paramType.getKey());
        try {
            this.custom = typeConversion(custom);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public final void uninstall(){
        custom = null;
    }

    /**
     * ParamType 在生成证书时候非常有用
     */
    public abstract ParamType paramType();
    /**
     * 自定义校验方法
     */
    public final boolean verify(T test){
        try {
            return verify(getCustom(), test);
        } catch (Exception e) {
            throw new RuntimeException("校验异常："+e.getMessage());
        }
    }

    /**
     * @param custom    自定义参数
     * @param test      校验
     * @return          校验是否通过
     */
    protected abstract boolean verify(T custom,T test);
    /**
     * 类型转换，调用者自定义的类型
     */
    protected abstract T typeConversion(Object custom) throws Exception;
    /**
     * 证书内的额外信息
     */
    public final T getCustom(){
        if (custom == null) {
            throw new RuntimeException("证书尚未安装!");
        }
        return custom;
    }

}
